# core/security.py
from datetime import datetime, timedelta,timezone
from typing import Optional
import jwt
from passlib.context import CryptContext
from fastapi import HTTPException, status, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session

from core.database import get_db
from db.models.users import UserDocument
from core.config import settings
from db.mysql.dao.users import UsersDAO, get_users_dao
from db.mysql.users import Users

# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# HTTP Bearer Token
security = HTTPBearer()


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码"""
    return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password: str) -> str:
    """获取密码哈希值"""
    return pwd_context.hash(password)


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    """创建访问令牌"""
    to_encode = data.copy()
    if expires_delta:
        expire =  datetime.now() + expires_delta
    else:
        expire = datetime.now() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
    return encoded_jwt


async def authenticate_user(username: str, password: str) -> Optional[UserDocument]:
    """验证用户"""
    user = await UserDocument.find_one({"username": username})
    if not user or not verify_password(password, user.hashed_password):
        return None
    return user

def authenticate_user_m(username: str, password: str):  # 移除 async 和 UserDocument 返回类型
    """验证用户 (支持 MySQL)"""
    dao = None
    try:
        dao = UsersDAO()
        user = dao.get_user_by_username(username)
        if not user or not verify_password(password, user.hashed_password):
            return None
        return user
    finally:
        if dao:
            dao.close()

def get_current_user_m(credentials: HTTPAuthorizationCredentials = Depends(security),
                       db: Session = Depends(get_db)) -> Users:
    """获取当前登录用户 (使用上下文管理器)"""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )

    token = credentials.credentials

    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except jwt.PyJWTError:
        raise credentials_exception

    # 使用上下文管理器
    dao = UsersDAO(db=db)
    user = dao.get_user_by_username(username)
    if user is None:
        raise credentials_exception
    return user

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)) -> UserDocument:
    """获取当前用户"""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )

    token = credentials.credentials

    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except jwt.PyJWTError:
        raise credentials_exception

    user = await UserDocument.find_one({"username": username})
    if user is None:
        raise credentials_exception
    return user


def get_current_active_user(current_user: UserDocument = Depends(get_current_user_m)) -> UserDocument:
    """获取当前活跃用户"""
    if not current_user.is_active:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user


def get_current_active_superuser(current_user: UserDocument = Depends(get_current_user)) -> UserDocument:
    """获取当前活跃超级用户"""
    if not current_user.is_superuser:
        raise HTTPException(
            status_code=400,
            detail="The user doesn't have enough privileges"
        )
    if not current_user.is_active:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user
